package org.springmole.web.controller;

import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.SessionStatus;
import org.springmole.business.bean.DbConnection;
import org.springmole.business.bean.QueryRequest;
import org.springmole.business.bean.Result;
import org.springmole.business.bean.ResultData;
import org.springmole.business.service.HibernateService;
import org.springmole.business.service.SpringMoleService;
import org.springmole.common.GeneralXMLException;


@Controller
public class XMLController {

	@Autowired
	private SpringMoleService springMoleService;
	
	@Autowired
	private HibernateService hibernateService;
	
	
	
	@RequestMapping(value="/openconnection.spy", method=RequestMethod.POST)
	public void processOpenConnectionGet(
			@ModelAttribute("dbConnection") DbConnection dbConnection,
			HttpServletResponse response, OutputStream outputStream) throws JAXBException {
		response.setContentType("text/xml");
		Result<? extends ResultData> result = springMoleService.openDbConnection(dbConnection);
		streamXMLResult(result, outputStream);
	}
	
	
	@RequestMapping(value="/openschema.spy", method=RequestMethod.POST)
	public void processOpenSchemaGet(
			@RequestParam(value="schemaName", required=true) String schemaName,
			@ModelAttribute("dbConnection") DbConnection dbConnection,
			HttpServletResponse response, OutputStream outputStream) throws JAXBException {
		response.setContentType("text/xml");
		Result<? extends ResultData> result = springMoleService.openSchema(dbConnection, schemaName);
		streamXMLResult(result, outputStream);
	}	
	
	
	@RequestMapping(value="/hibernate.spy", method=RequestMethod.GET, params="tableid=query_table_id")
	public void processHibernateQueryGet(
			HttpServletResponse response, OutputStream outputStream) throws JAXBException {
		response.setContentType("text/xml");
		Result<? extends ResultData> result = hibernateService.getQueryStatistic();
		streamXMLResult(result, outputStream);
	}
	
	
	@RequestMapping(value="/hibernate.spy", method=RequestMethod.GET, params="tableid=entity_table_id")
	public void processHibernateEntityGet(
			HttpServletResponse response, OutputStream outputStream) throws JAXBException {
		response.setContentType("text/xml");
		Result<? extends ResultData> result = hibernateService.getEntityStatistic();
		streamXMLResult(result, outputStream);
	}	
	
	
	@RequestMapping(value="/hibernate.spy", method=RequestMethod.GET, params="tableid=secondlevel_table_id")
	public void processHibernateSecondLevelGet(
			HttpServletResponse response, OutputStream outputStream) throws JAXBException {
		response.setContentType("text/xml");
		Result<? extends ResultData> result = hibernateService.getSecondLevelDataStatistics();
		streamXMLResult(result, outputStream);
	}
	
	
	@RequestMapping(value="/hibernate.spy", method=RequestMethod.GET, params="tableid=collection_table_id")
	public void processHibernateCollectionGet(
			HttpServletResponse response, OutputStream outputStream) throws JAXBException {
		response.setContentType("text/xml");
		Result<? extends ResultData> result = hibernateService.getCollectionStatistic();
		streamXMLResult(result, outputStream);
	}	
	
		
	/**
	 * http://codeangel.org/articles/xslt-transformation-with-jaxb.html
	 */
	@RequestMapping(value="/hibernate.spy", method=RequestMethod.GET, params="summary=content")
	public void processHibernateSummaryXhtmlGet(
			HttpServletRequest request,
			HttpServletResponse response, 
			OutputStream outputStream) throws JAXBException, TransformerConfigurationException {
		
		response.setContentType("text/html");

//		JAXBContext context = JAXBContext.newInstance(Result.class);
//		Marshaller marshaller = context.createMarshaller();
//		
//		Source xsltSource = new StreamSource(this.getClass().getResourceAsStream("/org/springmole/resource/xslt/hibernatesummary.xslt"));
//		
//		TransformerFactory transformerFactory = TransformerFactory.newInstance();
//		TransformerHandler transformerHandler = ((SAXTransformerFactory) transformerFactory).newTransformerHandler(xsltSource);
//		transformerHandler.setResult(new StreamResult(outputStream));
//		
//		Result<? extends ResultData> result = hibernateService.getSummaryDataStatistics();
//		marshaller.marshal(result, transformerHandler);
		
		Result<? extends ResultData> result = hibernateService.getSummaryDataStatistics();
		streamXHTMLResult(result, "/org/springmole/resource/xslt/hibernatesummary.xslt", outputStream);
	}
	
	
	@RequestMapping(value="/databasequery.spy", method=RequestMethod.POST)
	public void processDatabaseQueryXhtmlGet(
			@ModelAttribute("queryRequest") QueryRequest queryRequest,
			BindingResult result,
			SessionStatus status,
			ModelMap modelMap,
			HttpServletResponse response, 
			OutputStream outputStream) throws JAXBException, TransformerConfigurationException {
		
		response.setContentType("text/html");
		try {
			streamXHTMLResult(springMoleService.executeQuery(queryRequest), "/org/springmole/resource/xslt/hibernatesummary.xslt", outputStream);
		} catch (GeneralXMLException e) {
			e.printStackTrace();
		}
	}	
	
	
	@RequestMapping(value="/databasetable.spy", method=RequestMethod.POST)
	public void processQueryPost(
			@ModelAttribute("queryRequest") QueryRequest queryRequest,
			BindingResult result,
			SessionStatus status,
			ModelMap modelMap,
			HttpServletResponse response, 
			OutputStream outputStream) throws JAXBException {
		
		response.setContentType("text/xml");
		try {
			streamXMLResult(springMoleService.executeQuery(queryRequest), outputStream);
		} catch (GeneralXMLException e) {
			e.printStackTrace();
		}
	}		
	
	
	/**
	 * Helper method to wrap the JAXB usage.
	 * TODO: Create a bean factory of Marshaller for autowiring. (A Spring project may not have spring-ws.jar) 
	 * @param result
	 * @param outputStream
	 * @throws JAXBException
	 */
	private void streamXMLResult(Result<? extends ResultData> result, OutputStream outputStream) 
	throws JAXBException {
		JAXBContext context = JAXBContext.newInstance(Result.class);
		Marshaller marshaller = context.createMarshaller();
		marshaller.marshal(result, outputStream);
	}
	
	
	private void streamXHTMLResult(Result<? extends ResultData> result, String xsltResource , OutputStream outputStream) 
	throws JAXBException, TransformerConfigurationException {
		JAXBContext context = JAXBContext.newInstance(Result.class);
		Marshaller marshaller = context.createMarshaller();
		
		Source xsltSource = new StreamSource(this.getClass().getResourceAsStream(xsltResource));
		
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		TransformerHandler transformerHandler = ((SAXTransformerFactory) transformerFactory).newTransformerHandler(xsltSource);
		transformerHandler.setResult(new StreamResult(outputStream));
		
		marshaller.marshal(result, transformerHandler);		
	}
}
